<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>flood</title>
  <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0" />
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css" />
  <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  <script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js"></script>
  <script src="gl.js"></script>
  <script src="https://unpkg.com/leaflet-hash@0.2.1/leaflet-hash.js"></script>
  <style>
    #info {
      position: absolute;
      top: 50%;
      margin-top: -1.5em;
      height: auto;
      left: 0;
      right: 0;
      z-index: 2000;
      text-align: center;
      background: rgba(128, 0, 0, 0.8);
      color: white;
      padding: 2em 0;
    }

    #info.ready {
      cursor: pointer;
      background: rgba(0, 0, 128, 0.8);
    }

    #info.ready:hover {
      background: rgba(0, 0, 128, 1);
    }

    .leaflet-overlay-flood {
      opacity: 0.67;
    }

    #control {
      position: absolute;
      top: 5px;
      left: 5px;
      width: auto;
      height: auto;
      z-index: 2000;
    }
  </style>
</head>

<body>
  <div id="map" style="position:absolute;top:0;left:0;bottom:0;right:0;"></div>
  <div id="info">Hello</div>
  <div id="control">
    <select id="speed">
      <option value="1">very slow</option>
      <option value="2">slow</option>
      <option value="4" selected>normal</option>
      <option value="8">fast</option>
      <option value="16">very fast</option>
    </select>
  </div>
  <script>
    var fragmentShader =
      `
precision mediump float;
uniform sampler2D land;
uniform sampler2D rain;
uniform mat3 matrix;
uniform int dx;
uniform int dy;
uniform float delta;

float h(int dx,int dy){
  float x = dot(
    texture2D(land, (matrix * (gl_FragCoord.xyw + vec3(dx,dy,0))).xy),
    vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 0.0)
  );
  float s = sign(x - pow(2.0,23.0));
  return s < 0.0 ? x * 0.01 : (s > 0.0 ? (x - pow(2.0,24.0)) * 0.01 : - pow(2.0,24.0));
}
float r(int dx,int dy){
  return texture2D(rain, (matrix * (gl_FragCoord.xyw + vec3(dx,dy,0))).xy).a;
}

vec4 main1(){
  float h1 = h(-dx,-dy);
  float h2 = h(0, 0);
  float h3 = h(dx,dy);
  float r1 = r(-dx,-dy);
  float r2 = r(0, 0);
  float r3 = r(dx,dy);

  return (h2 <= -1000.0) ? vec4(0,0,0,0) :
    (r1>0.0 && h1+r1>h2+r2 && h2+r2<h3+r3) ? vec4(0,0,0.5,r2+delta/256.0) :
    (r2>0.0 && h2+r2>h3+r3 && (r1==0.0||r1+h1<r2+h2)) ? vec4(0,0,0.5,r2-delta/256.0) : vec4(0,0,0.5,r2);

}

vec4 main2(){
  float a = r(0,0);
  float s = sign(r(0,-1)) + sign(r(0,1)) + sign(r(1,0)) + sign(r(-1,0)) + sign(r(1,1))+ sign(r(-1,1))+ sign(r(1,-1))+ sign(r(-1,-1));
//  return
//    a < 0.01 ? vec4(0) :
//    a > 0.66 ? mix(vec4(1,0.6,0,0.75),vec4(1,0,0,0.75),(a-0.66) / 0.33)  :
//    a > 0.33 ? mix(vec4(0,0,1,0.75),vec4(1,0.6,0,0.75),(a-0.33) / 0.33)  :
//               mix(vec4(1,1,1,0.75),vec4(0,0,1,0.75),(a     ) / 0.33)  ;


vec4 colors[4];
colors[0] = vec4(8,8,8,8) / 8.0;
colors[1] = vec4(0,4,8,8) / 8.0;
colors[2] = vec4(0,0,8,8) / 8.0;
colors[3] = vec4(2,0,0,8) / 8.0;
float n = 1.0 / 3.0;
float p = mod(a,n) / n;

  return
    a == 0.0 ? vec4(0) :
    s < 8.0 ? vec4(0.3,0.1,0.0,1) :
    a > n * 2.0 ? mix(colors[2],colors[3], p) :
    a > n * 1.0 ? mix(colors[1],colors[2], p) :
                  mix(colors[0],colors[1], p);
}

void main(){
  gl_FragColor = matrix[1][1] < 0.0 ? main2() : main1();
}
`;
    var FloodOverlay = L.Layer.extend({
      initialize: function() {
        this._frames = [];
      },
      createLandTexture: function(map) {
        var s = map.getSize();
        var e = document.createElement("canvas");
        var c = e.getContext("2d");
        e.width = s.x;
        e.height = s.y;
        c.fillStyle = "#800000";
        c.fillRect(0, 0, s.x, s.y);

        map.eachLayer(function(layer) {
          if (!layer.options || layer.options.className !== "dempng-gsi") return;
          for (var key in layer._tiles) {
            var tile = layer._tiles[key];
            if (tile.current) {
              var p1 = layer._tileCoordsToNwSe(tile.coords)[0];
              var p2 = map.latLngToContainerPoint(p1);
              try {
                c.drawImage(tile.el, p2.x, p2.y);
              } catch (ex) {}
            }
          }
        });

        return e;
      },
      createRainTexture: function(map) {
        var s = map.getSize();
        var e = document.createElement("canvas");
        var c = e.getContext("2d");
        e.width = s.x;
        e.height = s.y;
        c.fillStyle = "rgba(0,0,0,0.25)";
        c.fillRect(1, 1, s.x - 2, s.y - 2);
        return e;
      },
      createDrawingCanvas: function(map) {
        var s = map.getSize();
        var e = document.createElement("canvas");
        e.setAttribute("class", "leaflet-overlay-flood");
        e.width = s.x;
        e.height = s.y;
        return e;
      },
      onAdd: function(map) {
        var canvas = this.createDrawingCanvas(map);
        var land = this.createLandTexture(map);
        var rain = this.createRainTexture(map);

        this.getPane().appendChild(canvas);
        L.DomUtil.setPosition(canvas, map.containerPointToLayerPoint([0, 0]));

        var gl = $gl(canvas.getContext("webgl"))
          .shader("attribute vec2 xy;void main(){gl_Position = vec4(xy,0,1);}")
          .shader(fragmentShader)
          .bind("xy", [-1, -1, 1, -1, -1, 1, 1, 1])
          .texture(0, land)
          .texture(1, rain)
          .texture(2, rain)
          .bind("land", 0)
          .viewport(0, 0, canvas.width, canvas.height);

        this._canvas = canvas;
        this._gl = gl;

        this.start();
      },
      onRemove: function(map) {
        L.DomUtil.remove(this._canvas);
      },
      stop: function() {
        while (this._frames.length > 0) L.Util.cancelAnimFrame(this._frames.pop());
      },
      start: function() {

        this.stop();

        var canvas = this._canvas;
        var gl = this._gl;

        this._frames.push(L.Util.requestAnimFrame(function() {

          var deltas = [
            [1, 1],
            [1, 0],
            [1, -1],
            [0, 1],
            [0, -1],
            [-1, 1],
            [-1, 0],
            [-1, -1],
          ];

          var p = deltas[Math.floor(deltas.length * Math.random())];
          gl.bind("matrix", [1 / canvas.width, 0, 0, 0, 1 / canvas.height, 0, 0, 0, 0])
            .bind("rain", 1)
            .bind("dx", p[0])
            .bind("dy", p[1])
            .bind("delta", parseFloat($("#speed").val()))
            .triangleStrip(2)
            .bind("matrix", [1 / canvas.width, 0, 0, 0, 1 / canvas.height, 0, 0, 0, 0])
            .bind("rain", 2)
            .triangleStrip(1)
            .bind("matrix", [1 / canvas.width, 0, 0, 0, -1 / canvas.height, 0, 0, 1, 0])
            .bind("rain", 1)
            .triangleStrip();

          this.stop();
          this.start();
        }, this));
      }
    });

    var map = L.map("map", L.extend({
      zoom: 15,
      center: [35.6723, 139.7017],
      maxZoom: 15
    }, L.Hash.parseHash(location.hash)));
    map.zoomControl.setPosition("bottomright");
    L.hash(map);

    L.control.layers({
      "淡色地図": L.tileLayer("https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png", {
        attribution: "<a href='http://maps.gsi.go.jp/development/ichiran.html'>地理院タイル</a>"
      }).addTo(map),
      "写真": L.tileLayer("https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg", {
        attribution: "<a href='http://maps.gsi.go.jp/development/ichiran.html'>地理院タイル</a>"
      }),
      "陰影": L.tileLayer("https://cyberjapandata.gsi.go.jp/xyz/hillshademap/{z}/{x}/{y}.png", {
        attribution: "<a href='http://maps.gsi.go.jp/development/ichiran.html'>地理院タイル</a>"
      }),
      "OpenStreetMap": L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
        attribution: "&copy; <a href='http://osm.org/copyright'>OpenStreetMap</a> contributors"
      })
    }).addTo(map);


    var focus = null;

    $("#info").click(function() {
      if ($(this).is(".ready")) {
        if (focus === null)
          focus = new FloodOverlay().addTo(map);
        $("#info").hide();
      }
    });

    L.tileLayer("https://cyberjapandata.gsi.go.jp/xyz/{id}/{z}/{x}/{y}.png?qxz", {
      crossOrigin: true,
      opacity: 0,
      attribution: "<a href='http://maps.gsi.go.jp/development/ichiran.html'>地理院タイル</a>",
      className: "dempng-gsi",
      id: function(coords) {
        return coords.z === 15 ? "dem5a_png" : "dem_png";
      }
    }).on("loading", function() {
      $("#info").removeClass("ready").text("Loading DEM tiles").show();
      if (focus) {
        focus.stop();
        map.removeLayer(focus);
        focus = null;
      }
    }).on("load", function() {
      $("#info").addClass("ready").text("Click to Run").show();
    }).addTo(map);
  </script>
</body>

</html>
